package com.yfbao.web.gateway.config;

import com.yfbao.web.gateway.ops.AuthService;
import com.yfbao.web.gateway.router.TokenInterceptor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

@Configuration
public class OkHttpConfig {

//    @Autowired
//    private AuthService authService;

    @Bean
    public OkHttpClient okHttpClient() {
        return new OkHttpClient.Builder()
                .connectTimeout(5000, TimeUnit.MILLISECONDS)
                .readTimeout(30000, TimeUnit.MILLISECONDS)
                .writeTimeout(30000, TimeUnit.MILLISECONDS)
                .connectionPool(new ConnectionPool(200, 5, TimeUnit.MINUTES))
                .addInterceptor(new LoggingInterceptor())
                .addInterceptor(new RetryInterceptor())
                .addInterceptor(new TokenInterceptor(new AuthService()))
                .build();
    }

    /**
     * 日志拦截器
     */
    @Slf4j
    public static class LoggingInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            long startTime = System.nanoTime();

            log.info("发送请求: {} {}", request.method(), request.url());

            Response response = chain.proceed(request);

            long endTime = System.nanoTime();
            log.info("收到响应: {} {} 耗时: {}ms",
                    response.code(), response.message(),
                    (endTime - startTime) / 1000000);

            return response;
        }
    }

    /**
     * 重试拦截器
     */
    public static class RetryInterceptor implements Interceptor {
        private static final int MAX_RETRIES = 3;

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response = null;
            IOException exception = null;

            // 重试逻辑
            for (int i = 0; i < MAX_RETRIES; i++) {
                try {
                    // 关闭之前的响应（如果不是第一次尝试）
                    if (response != null) {
                        response.close();
                    }

                    response = chain.proceed(request);

                    // 对于401认证错误，不应该重试，应该立即返回让TokenInterceptor处理
                    if (response.code() == 401 || response.isSuccessful() || i == MAX_RETRIES - 1) {
                        return response;
                    }

                    // 只对特定的可重试错误进行重试
                    if (!shouldRetry(response.code())) {
                        return response;
                    }
                } catch (IOException e) {
                    exception = e;
                    // 如果达到最大重试次数，抛出异常
                    if (i == MAX_RETRIES - 1) {
                        throw e;
                    }

                    // 对于连接超时等网络异常可以重试
                    if (!isNetworkError(e)) {
                        throw e;
                    }
                }

                // 等待后重试（不在最后一次尝试后等待）
                if (i < MAX_RETRIES - 1) {
                    try {
                        Thread.sleep(1000 * (i + 1)); // 指数退避
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        throw new IOException("重试被中断", ie);
                    }
                }
            }

            // 这行代码实际上不会执行到，因为上面已经return或throw了异常
            if (exception != null) {
                throw exception;
            }

            return response;
        }

        /**
         * 判断是否应该重试
         */
        private boolean shouldRetry(int code) {
            // 5xx服务器错误和429限流错误可以重试
            return code >= 500 || code == 429;
        }

        /**
         * 判断是否为网络错误
         */
        private boolean isNetworkError(IOException e) {
            // 可以根据具体异常类型判断是否为网络错误
            return true; // 简化处理，实际可根据需要细化
        }
    }


}
